package com.appshelves;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;

import com.appshelves.layout.AppGrid;
import com.appshelves.layout.AppGrid.IOnBuildListener;
import com.appshelves.layout.Cell;
import com.appshelves.layout.Dialogs;
import com.appshelves.layout.Dialogs.DialogListener;
import com.appshelves.layout.ModelBinder;
import com.appshelves.layout.ShelfLayout;
import com.appshelves.layout.helpers.IAppClickListener;
import com.appshelves.layout.helpers.ScrollCellAligner;
import com.appshelves.layout.widgets.TunedButton;
import com.appshelves.model.App;
import com.appshelves.model.Model;
import com.appshelves.model.Model.Event;
import com.appshelves.model.Model.EventListener;
import com.appshelves.model.Shelf;
import com.appshelves.utils.Profiler;
import com.appshelves.utils.Utils;

public class ShelfEditActivity extends EventListenerActivity {

    private ArrayList<App> toAdd;
    private ArrayList<App> toRemove;
    private IAppClickListener gridListener;
    private IAppClickListener shelfListener;
    private AppGrid grid;
    private ShelfLayout demoShelf;
    private ScrollView scroll;
    private TunedButton changesIndicator;
    private TunedButton optionsButton;
    private Shelf shelfToEdit;
    private TextView caption;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Profiler p = new Profiler(this, "loading....");
        Utils.setContext(this);

        toAdd = new ArrayList<App>();
        toRemove = new ArrayList<App>();

        initLayout();
        p.e();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_edit, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.findItem(R.id.menu_delete_shelf).setEnabled(shelfToEdit != null);
        menu.findItem(R.id.menu_discard_changes).setEnabled(somethingChanged());

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_delete_shelf:
                deleteShelf();
                return true;
            case R.id.menu_discard_changes:
                discardChanges();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        performChanges();
        super.onBackPressed();
    }

    @Override
    protected void onPause() {
        super.onPause();
        ModelBinder.popBinds();
        grid.cancelAsyncTasks();
    }

    /// layout initialization.

    private void initLayout() {
        setContentView(R.layout.shelf_edit);

        initPaddings();

        initShelf();
        initGrid();
        scroll = (ScrollView) findViewById(R.id.scroll_view);

        initTop();
        updateCaption();
    }

    private void initShelf() {
        demoShelf = (ShelfLayout) findViewById(R.id.shelf_demo);
        demoShelf.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, Settings.cellHeight));
        shelfListener = new ShelfListener();
        demoShelf.setListener(shelfListener);

        shelfToEdit = Model.getShelfToChange();
        initShelfApps();
    }

    private void initShelfApps() {
        if (shelfToEdit == null)
            return;
        List<App> apps = Model.getShelfApps(shelfToEdit);
        ModelBinder.pushBinds(apps); // new cells for the apps are created, so we have to store the binds
        demoShelf.addApps(apps);
    }

    private void initGrid() {
        grid = (AppGrid) findViewById(R.id.app_grid);
        gridListener = new GridListener();
        grid.init(gridListener, new IOnBuildListener() {

            @Override
            public void onBuilded() {
                ScrollCellAligner.addCellAligner(scroll);
            }
        });
    }

    private void initPaddings() {
        initChildPadding(R.id.main_view, Settings.paddingLeft, 0, Settings.paddingRight, Settings.paddingBottom);
        initChildPadding(R.id.top_bar, Settings.marginHor, 0, 0, 0); // button will handle the right padding.
        initChildPadding(R.id.separator_1, Settings.marginHor, Settings.marginVer, Settings.marginHor,
            Settings.marginVer);
        initChildPadding(R.id.separator_2, Settings.marginHor, Settings.marginVer, Settings.marginHor,
            Settings.marginVer);
    }

    private void initChildPadding(int viewID, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
        findViewById(viewID).setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    }

    private void initTop() {
        caption = (TextView) findViewById(R.id.text_caption);
        caption.setTextSize(TypedValue.COMPLEX_UNIT_PX, Settings.getCaptionSize());

        changesIndicator = (TunedButton) findViewById(R.id.button_confirm);
        changesIndicator.tuneToTextView(caption);

        optionsButton = (TunedButton) findViewById(R.id.button_options);
        if (!ViewConfiguration.get(this).hasPermanentMenuKey()) { // leaving optionsButton invisible if there is no need in it.
            optionsButton.tuneToTextView(caption);
            optionsButton.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    openOptionsMenu();
                }
            });
        }

        indicatorOnNoChanges();
    }

    ///

    private void updateUI() {
        updateCaption();
        updateIndicator();
    }

    /// caption

    private void updateCaption() {
        int captionID = R.string.edit_caption_add_remove;
        if (Model.getOffShelfAppsNumber() == 0) {
            if (shelfToEdit == null || Model.getShelfAppsNumber(shelfToEdit) == null)
                captionID = R.string.edit_caption_no_apps;
            else
                captionID = R.string.edit_caption_remove;
        } else if (shelfToEdit == null)
            captionID = R.string.edit_caption_add;

        setCaption(captionID);
    }

    private void setCaption(int captionID) {
        caption.setText(captionID);
    }

    /// button 

    private void updateIndicator() {
        if (somethingChanged())
            indicatorOnChanged();
        else
            indicatorOnNoChanges();
    }

    private void indicatorOnChanged() {
        changesIndicator.setVisibility(View.VISIBLE);
    }

    private void indicatorOnNoChanges() {
        changesIndicator.setVisibility(View.GONE);
    }

    /// changes

    private boolean somethingChanged() {
        return toAdd.size() != 0 || toRemove.size() != 0;
    }

    private void onAppRemovedFromDemoShelf(App app) {
        if (Model.isOffShelfApp(app))
            toAdd.remove(app);
        else
            toRemove.add(app);
    }

    private void onAppAddedToDemoShelf(App app) {
        if (Model.isOffShelfApp(app))
            toAdd.add(app);
        else
            toRemove.remove(app);
    }

    private void performChanges() {
        if (!somethingChanged())
            return;

        Model.requestAddAppsToShelf(toAdd);
        Model.requestRemoveAppsFromShelf(toRemove);
        finish();
    }

    private void discardChanges() {
        List<Cell> removedFromShelf = demoShelf.removeApps(toAdd);
        grid.insertCells(removedFromShelf);
        toAdd.clear();

        if (shelfToEdit != null) {
            List<Cell> removedFromGrid = grid.removeApps(toRemove);
            demoShelf.insertCells(shelfToEdit, removedFromGrid);
            toRemove.clear();
        }

        updateUI();
    }

    ///

    private void deleteShelf() {
        Dialogs.showConfirmDialog(this, R.string.dialog_delete, new DialogListener() {

            @Override
            public void onConfirm() {
                Model.requestDeleteShelf();
                finish();
            }

            @Override
            public void onCancel() {
            }
        });
    }

    ///

    @Override
    protected void addEventListeners() {
        addEventListener(Event.OFF_SHELF_APP_ADDED, new EventListener() {

            @Override
            public void onEvent(Object args) {
                onOffShelfAppAdded((App) args);
            }
        });

        addEventListener(Event.OFF_SHELF_APP_DELETED, new EventListener() {

            @Override
            public void onEvent(Object args) {
                onAppDeleted((App) args);
            }
        });

        addEventListener(Event.APP_UNINSTALLED, new EventListener() {

            @Override
            public void onEvent(Object args) {
                onAppUninstalled((App) args);
            }
        });

        if (shelfToEdit != null)
            Model.addListener(shelfToEdit, Event.APP_REMOVED_FROM_SHELF, new EventListener() {

                @Override
                public void onEvent(Object args) {
                    onAppDeleted((App) args);
                }
            });

    }

    private void onOffShelfAppAdded(App app) {
        grid.insertApp(app);
        updateUI();
        Utils.showAppToast(R.string.toast_app_installed, app);
    }

    private void onAppDeleted(App app) {
        Cell cell = ModelBinder.getCellByApp(app);
        cell.removeFromParent();
        toRemove.remove(app);
        toAdd.remove(app);
        updateUI();
    }

    private void onAppUninstalled(App app) {
        Utils.showAppToast(R.string.toast_app_uninstalled, app);
    }

    /// helpers.

    private void removeCellFromPreviousPlace(Cell cell) {
        cell.removeFromParent();
    }

    private class GridListener implements IAppClickListener {
        @Override
        public void onAppClick(App app, Cell cell) {
            removeCellFromPreviousPlace(cell);
            onAppAddedToDemoShelf(app);

            demoShelf.addCell(cell);
            cell.setAppClickedListener(shelfListener);

            updateUI();
        }
    }

    private class ShelfListener implements IAppClickListener {
        @Override
        public void onAppClick(App app, Cell cell) {
            removeCellFromPreviousPlace(cell);
            onAppRemovedFromDemoShelf(app);

            grid.addView(cell, 0, new AppGrid.LayoutParams());
            cell.setAppClickedListener(gridListener);

            updateUI();
        }
    }

}